In [2]:
from IPython.display import Image
In [3]:
Image("res4.gif")
Out[3]:
For this simple circuit the questions are
For each we will assume also that the 12V is not perfect.
We will try and answer these questions for the circuit as designed and also for the cuircuit as built with a few measurments of the resistors and see how that impacts the results.
The results are:
$R_{eff} = 6\Omega$
$I_T = 1A, I_1 = I_2 = 0.5A$
In [5]:
import numpy as np
import matplotlib.pyplot as plt
import pymc3 as pm
import pandas as pd
import seaborn as sns
sns.set()
%matplotlib inline
Each component is assumed to be a normal distriubution of exptected value as listed and the 4, 6, 8 Ohm resistors are 1% while the 12 Ohm is a 5% resistor.
Per http://docs.pymc.io/api/bounds.html we will use bounded variables because resistances that are negative are nonsensical.
In [6]:
## setup the model
# these are the values and precision of each
Datasheets = {'R1':(6.0, 0.01),
'R2':(8.0, 0.01),
'R3':(4.0, 0.01),
'R4':(12.0, 0.05),
'V1':(6.0, 0.01),} # 1% on the 12V power supply
with pm.Model() as model:
BoundedNormal = pm.Bound(pm.Normal, lower=0.0)
# http://docs.pymc.io/api/distributions/continuous.html#pymc3.distributions.continuous.Normal
# in Bayes world these are considered prior distributions, they are based on previous information
# that is gained in some other manner, from the datasheet in this case.
R1 = BoundedNormal('R1', mu=Datasheets['R1'][0], sd=Datasheets['R1'][0]*Datasheets['R1'][1])
R2 = BoundedNormal('R2', mu=Datasheets['R2'][0], sd=Datasheets['R2'][0]*Datasheets['R2'][1])
R3 = BoundedNormal('R3', mu=Datasheets['R3'][0], sd=Datasheets['R3'][0]*Datasheets['R3'][1])
R4 = BoundedNormal('R4', mu=Datasheets['R4'][0], sd=Datasheets['R4'][0]*Datasheets['R4'][1])
# don't bound the voltage as negative is possilbe
V1 = pm.Normal('V1', mu=Datasheets['V1'][0], sd=Datasheets['V1'][0]*Datasheets['V1'][1])
# Match should all be done on paper first to get the full answer, but we will do steps here because one can.
# all at once would be much faster.
# just add them, we will not get info on R2_3 at the output unless we wrap them in pm.Deterministic
R2_3 = R2+R3
# R2_3 = pm.Deterministic('R2_3', R2+R3)
# now get the resistance answer, and we want details
R_eff = pm.Deterministic('R_eff', 1/(1/R2_3 + 1/R4))
# total current is then just I=V/R
I_t = pm.Deterministic('I_t', V1/R_eff)
# and I_1 and I_2
I_1 = pm.Deterministic('I_1', I_t*R2_3/R4)
I_2 = pm.Deterministic('I_2', I_t-I_1)
# makes it all a bit clearner to start in a good place
start = pm.find_MAP()
# run a fair number of samples, I have a 8 core machine so run 6
trace = pm.sample(5000, start=start, njobs=6)
In the summary what is shown is the variable name ans summary information about each variable.
We see that:
$R_{eff} = 5.997 \pm 0.3$, really $R_{eff}$ is between $[5.705, 6.302]$
or $6\Omega \pm 5\%$
$I_t = 1.001 \pm 0.113$, $[0.892, 1.113]$
or $1.001 \pm 11\%$
So if one is going for a 5% accuracy on the current you cannot say that!
In [7]:
I_t_perc = np.percentile(trace['I_t'], (2.5, 97.5))
I_t_mean = trace['I_t'].mean()
print('I_t = {:.4} +/- {:.4}'.format(I_t_mean, I_t_perc[1]-I_t_mean))
print('I_t = {:.4} +/- {:.4}%'.format(I_t_mean, (I_t_perc[1]-I_t_mean)/I_t_mean*100))
In [8]:
pm.summary(trace, varnames=('R_eff', 'I_t', 'I_1', 'I_2'))
Out[8]:
We also good visual diagnostics in terms of traceplots. The right side shows the draws, this should always look like hash, the left side is the Kernel Density Esimator of the output distribution. For this problem it should look pretty darn Normal.
For both summary and traceplot, leavre off varnames to jst get them all...
In [9]:
pm.traceplot(trace, combined=True, varnames=('R_eff', 'I_t'));
In [ ]:
# setup the model
# these are the values and precision of each
Datasheets = {'R1':(6.0, 0.01),
'R2':(8.0, 0.01),
'R3':(4.0, 0.01),
'R4':(12.0, 0.05),
'V1':(6.0, 0.05),} # 5% on the 12V power supply
measuremnts_R1 = [5.987, 5.987] # we measured it twice
with pm.Model() as model:
# http://docs.pymc.io/api/distributions/continuous.html#pymc3.distributions.continuous.Normal
# in Bayes world these are considered prior distributions, they are based on previous information
# that is gained in some other manner, from the datasheet in this case.
# R1 = pm.Normal('R1', mu=Datasheets['R1'][0], sd=Datasheets['R1'][0]*Datasheets['R1'][1])
R2 = pm.Normal('R2', mu=Datasheets['R2'][0], sd=Datasheets['R2'][0]*Datasheets['R2'][1])
R3 = pm.Normal('R3', mu=Datasheets['R3'][0], sd=Datasheets['R3'][0]*Datasheets['R3'][1])
R4 = pm.Normal('R4', mu=Datasheets['R4'][0], sd=Datasheets['R4'][0]*Datasheets['R4'][1])
# don't bound the voltage as negative is possilbe
V1 = pm.Normal('V1', mu=Datasheets['V1'][0], sd=Datasheets['V1'][0]*Datasheets['V1'][1])
# so on R1 we took some measurments and so have to build it a bit differently
# use the datasheet for prior
R1_mean = pm.Normal('R1_mean', mu=Datasheets['R1'][0], sd=Datasheets['R1'][0]*Datasheets['R1'][1])
R1 = pm.Normal('R1', mu=R1_mean, sd=Datasheets['R1'][0]*Datasheets['R1'][1], observed=measuremnts_R1)
# Match should all be done on paper first to get the full answer, but we will do steps here because one can.
# all at once would be much faster.
# just add them, we will not get info on R2_3 at the output unless we wrap them in pm.Deterministic
R2_3 = R2+R3
# R2_3 = pm.Deterministic('R2_3', R2+R3)
# now get the resistance answer, and we want details
R_eff = pm.Deterministic('R_eff', 1/(1/R2_3 + 1/R4))
# total current is then just I=V/R
I_t = pm.Deterministic('I_t', V1/R_eff)
# and I_1 and I_2
I_1 = pm.Deterministic('I_1', I_t*R2_3/R4)
I_2 = pm.Deterministic('I_2', I_t-I_1)
# makes it all a bit clearner to start in a good place
start = pm.find_MAP()
# run a fair number of samples, I have a 8 core machine so run 6
trace = pm.sample(5000, start=start, njobs=6)
In [ ]:
pm.summary(trace, varnames=('R_eff', 'I_t', 'I_1', 'I_2'))
In [ ]:
pm.traceplot(trace, combined=True, varnames=('R_eff', 'I_t'));
In [55]:
I_t_perc = np.percentile(trace['I_t'], (2.5, 97.5))
I_t_mean = trace['I_t'].mean()
print('I_t = {:.4} +/- {:.4}'.format(I_t_mean, I_t_perc[1]-I_t_mean))
print('I_t = {:.4} +/- {:.4}%'.format(I_t_mean, (I_t_perc[1]-I_t_mean)/I_t_mean*100))
In [56]:
# setup the model
# these are the values and precision of each
Datasheets = {'R1':(6.0, 0.01),
'R2':(8.0, 0.01),
'R3':(4.0, 0.01),
'R4':(12.0, 0.01), # better resistor
'V1':(6.0, 0.05),} # 5% on the 12V power supply
with pm.Model() as model:
BoundedNormal = pm.Bound(pm.Normal, lower=0.0)
# http://docs.pymc.io/api/distributions/continuous.html#pymc3.distributions.continuous.Normal
# in Bayes world these are considered prior distributions, they are based on previous information
# that is gained in some other manner, from the datasheet in this case.
R1 = BoundedNormal('R1', mu=Datasheets['R1'][0], sd=Datasheets['R1'][0]*Datasheets['R1'][1])
R2 = BoundedNormal('R2', mu=Datasheets['R2'][0], sd=Datasheets['R2'][0]*Datasheets['R2'][1])
R3 = BoundedNormal('R3', mu=Datasheets['R3'][0], sd=Datasheets['R3'][0]*Datasheets['R3'][1])
R4 = BoundedNormal('R4', mu=Datasheets['R4'][0], sd=Datasheets['R4'][0]*Datasheets['R4'][1])
# don't bound the voltage as negative is possilbe
V1 = pm.Normal('V1', mu=Datasheets['V1'][0], sd=Datasheets['V1'][0]*Datasheets['V1'][1])
# Match should all be done on paper first to get the full answer, but we will do steps here because one can.
# all at once would be much faster.
# just add them, we will not get info on R2_3 at the output unless we wrap them in pm.Deterministic
R2_3 = R2+R3
# R2_3 = pm.Deterministic('R2_3', R2+R3)
# now get the resistance answer, and we want details
R_eff = pm.Deterministic('R_eff', 1/(1/R2_3 + 1/R4))
# total current is then just I=V/R
I_t = pm.Deterministic('I_t', V1/R_eff)
# and I_1 and I_2
I_1 = pm.Deterministic('I_1', I_t*R2_3/R4)
I_2 = pm.Deterministic('I_2', I_t-I_1)
# makes it all a bit clearner to start in a good place
start = pm.find_MAP()
# run a fair number of samples, I have a 8 core machine so run 6
trace = pm.sample(5000, start=start, njobs=6)
In [57]:
I_t_perc = np.percentile(trace['I_t'], (2.5, 97.5))
I_t_mean = trace['I_t'].mean()
print('I_t = {:.4} +/- {:.4}'.format(I_t_mean, I_t_perc[1]-I_t_mean))
print('I_t = {:.4} +/- {:.4}%'.format(I_t_mean, (I_t_perc[1]-I_t_mean)/I_t_mean*100))
The better resistor helped but are are dominated somewhere else... power supply!
In [ ]: